58. 绘制饼图

饼图:比例的可视化

饼图(Pie Chart)是展示部分与整体关系的经典工具

在金融分析中,饼图帮助我们:

  • 资产配置:展示投资组合的构成
  • 收入结构:主营业务与其他业务的占比
  • 市场份额:不同公司的市场占有率
  • 行业分布:投资的行业配置

饼图的数学基础

饼图将圆划分为若干扇形,每个扇形的角度对应一个类别的比例:

\[\theta_i = \frac{x_i}{\sum_{j=1}^n x_j} \times 360°\]

其中:

  • \(x_i\):第 \(i\) 个类别的数值
  • \(\theta_i\):第 \(i\) 个扇形的角度

⭐ 平台任务1:创建融资存量数据框

Listing 1
# ⚠️ 平台原始代码 - 请原样输入至教学平台(注释除外),平台才会判定答案正确
import pandas as pd  # 导入Pandas数据分析库

import numpy as np  # 导入NumPy数值计算库

time=['2018年12月末','2019年3月末','2019年6月末','2019年9月末']#创建日期的列表

name=['人民币贷款','债券','委托贷款','信托贷款','股票','承兑汇票','贷款核销','外币贷款']#创建指标名称的列表

# 创建NumPy数组datas
datas=np.array([[134.69,140.98,144.71,148.58],[29.25,30.53,31.89,33.54],[12.36,12.15,11.89,11.73],[7.85,7.88,7.88,7.68],[7.01,7.06,7.13,7.24],[3.81,4.01,3.77,3.28],[3.01,3.18,3.43,3.66],

[2.21,2.18,2.21,2.19]])#创建具体数据的数组

AFRE = pd.DataFrame(data=datas,index=name,columns=time)  # 创建数据框AFRE

print(AFRE)  # 输出变量AFRE的值
       2018年12月末  2019年3月末  2019年6月末  2019年9月末
人民币贷款     134.69    140.98    144.71    148.58
债券         29.25     30.53     31.89     33.54
委托贷款       12.36     12.15     11.89     11.73
信托贷款        7.85      7.88      7.88      7.68
股票          7.01      7.06      7.13      7.24
承兑汇票        3.81      4.01      3.77      3.28
贷款核销        3.01      3.18      3.43      3.66
外币贷款        2.21      2.18      2.21      2.19

⭐ 平台任务2:绘制基础饼图

# ⚠️ 平台原始代码 - 请原样输入至教学平台(注释除外),平台才会判定答案正确
import matplotlib.pyplot as plt  # 导入Matplotlib绑图库
import pandas as pd  # 导入Pandas数据分析库
import numpy as np  # 导入NumPy数值计算库
plt.rcParams["font.sans-serif"] = ["SimHei"]  # 设置Matplotlib全局参数
time=['2018年12月末','2019年3月末','2019年6月末','2019年9月末']#创建日期的列表
name=['人民币贷款','债券','委托贷款','信托贷款','股票','承兑汇票','贷款核销','外币贷款']#创建指标名称的列表
# 创建NumPy数组datas
datas=np.array([[134.69,140.98,144.71,148.58],[29.25,30.53,31.89,33.54],[12.36,12.15,11.89,11.73],[7.85,7.88,7.88,7.68],[7.01,7.06,7.13,7.24],[3.81,4.01,3.77,3.28],[3.01,
3.18,3.43,3.66],[2.21,2.18,2.21,2.19]])#创建具体数据的数组
AFRE = pd.DataFrame(data=datas,index=name,columns=time)  # 创建数据框AFRE
plt.figure(figsize=(9,6))  # 创建图形画布
plt.pie(x=AFRE.iloc[:,-1],labels=AFRE.index,textprops={"fontsize":13}) #绘制2018年末各项融资存量的饼图
plt.axis("equal") #使饼图是一个图形
plt.legend(fontsize=12)  # 添加图例
plt.title(u"2019年9月末各类融资存量的占比",fontsize=13)  # 设置图表标题
plt.show()  # 显示图形
plt.savefig("1.png")  # 保存图形至文件
Listing 2
(a) 基础饼图——投资组合配置
(b)
<Figure size 960x480 with 0 Axes>

⭐ 平台任务3:绘制多子图饼图

# ⚠️ 平台原始代码 - 请原样输入至教学平台(注释除外),平台才会判定答案正确
import matplotlib.pyplot as plt  # 导入Matplotlib绑图库
import pandas as pd  # 导入Pandas数据分析库
import numpy as np  # 导入NumPy数值计算库
plt.rcParams["font.sans-serif"] = ["SimHei"]  # 设置Matplotlib全局参数
time=['2018年12月末','2019年3月末','2019年6月末','2019年9月末']#创建日期的列表
name=['人民币贷款','债券','委托贷款','信托贷款','股票','承兑汇票','贷款核销','外币贷款']#创建指标名称的列表
# 创建NumPy数组datas
datas=np.array([[134.69,140.98,144.71,148.58],[29.25,30.53,31.89,33.54],[12.36,12.15,11.89,11.73],[7.85,7.88,7.88,7.68],[7.01,7.06,7.13,7.24],[3.81,4.01,3.77,3.28],[3.01,
3.18,3.43,3.66],[2.21,2.18,2.21,2.19]])#创建具体数据的数组
AFRE = pd.DataFrame(data=datas,index=name,columns=time)  # 创建数据框AFRE
plt.figure(figsize=(11,11))  # 创建图形画布
plt.subplot(2,2,1)#第1行、第1列子图
plt.pie(x=AFRE.iloc[:,0],labels=AFRE.index,labeldistance=1.03,counterclock=False,textprops={'fontsize':12})#绘制2018年12月末各项融资存量的饼图
plt.axis('equal')#使饼图是一个圆形
plt.title(u"2018年12月末",fontsize=14)  # 设置图表标题
plt.subplot(2,2,2)#第1行、第2列子图
plt.pie(x=AFRE.iloc[:,1],labels=AFRE.index,labeldistance=1.03,counterclock=False,textprops={'fontsize':12})#绘制2019年3月末各项融资存量的饼图
plt.axis('equal')#使饼图是一个圆形
plt.title(u"2019年3月末",fontsize=14)  # 设置图表标题
plt.subplot(2,2,3)#第2行、第1列子图
plt.pie(x=AFRE.iloc[:,2],labels=AFRE.index,labeldistance=1.03,counterclock=False,textprops={'fontsize':12})#绘制2019年6月末各项融资存量的饼图
plt.axis('equal')#使饼图是一个圆形
plt.title(u"2019年6月末",fontsize=14)  # 设置图表标题
plt.subplot(2,2,4)#第2行、第2列子图
plt.pie(x=AFRE.iloc[:,3],labels=AFRE.index,labeldistance=1.03,counterclock=False,textprops={'fontsize':12})#绘制2019年9月末各项融资存量的饼图
plt.axis('equal')#使饼图是一个圆形
plt.title(u"2019年9月末",fontsize=14)  # 设置图表标题
plt.show()  # 显示图形
plt.savefig("2.png")  # 保存图形至文件
Listing 3
(a)
(b)
<Figure size 960x480 with 0 Axes>

饼图关键参数解析

参数 说明 示例
autopct 显示百分比格式 '%1.1f%%' 保留1位小数
startangle 起始角度 90 从12点方向开始
explode 突出显示 (0.1, 0, 0) 第一块偏移
labeldistance 标签距圆心距离 1.03 略大于半径
counterclock 是否逆时针 False 顺时针排列

环形图:更现代的饼图

环形图(甜甜圈图)在饼图中心挖空,可放置额外信息

环形图的优势

  • 更现代、美观的视觉效果
  • 中心可放置额外信息(总计、图标等)
  • 减小扇形面积的视觉误导

环形图代码实现

import matplotlib.pyplot as plt

# ==================== 收入数据 ====================
revenue_sources = ['主营业务', '其他业务', '投资收益', '资产处置']
revenues = [850, 120, 80, 50]  # 各项收入,单位:亿元
colors_revenue = ['#2E86AB', '#008080', '#F0A700', '#E3120B']

# ==================== 绘制环形图 ====================
fig, ax = plt.subplots(figsize=(8, 8))

wedges, texts, autotexts = ax.pie(
    revenues, labels=revenue_sources,
    colors=colors_revenue, autopct='%1.1f%%',
    startangle=90, pctdistance=0.85)

# 创建白色圆心,形成环形效果
center_circle = plt.Circle((0, 0), 0.60, fc='white')
ax.add_artist(center_circle)

# 在中心添加总计信息
total_revenue = sum(revenues)
ax.text(0, 0, f'总收入\n{total_revenue}亿元',
        ha='center', va='center', fontsize=14, fontweight='bold')

plt.title('收入构成', fontsize=16, fontweight='bold', pad=20)
plt.tight_layout()
plt.show()
Figure 1: 环形图——收入构成分析

条形图 vs 饼图:如何选择?

场景 推荐图表 理由
类别≤5,重点是构成 饼图 直观展示比例
类别>5 条形图 避免饼图过于细碎
需要精确比较数值 条形图 长度比角度更易比较
层次结构 环形图/嵌套饼图 展示多级构成
时间序列变化 堆叠条形图 饼图难以展示变化

条形图与饼图对比示例

import matplotlib.pyplot as plt
import numpy as np

# ==================== 市场份额数据 ====================
companies = ['公司A', '公司B', '公司C', '公司D', '公司E']
market_share = [35, 25, 20, 12, 8]
colors_comparison = ['#E3120B', '#008080', '#F0A700', '#2C3E50', '#8E9EAA']

fig, axes = plt.subplots(1, 2, figsize=(14, 6))

# 左:饼图
axes[0].pie(market_share, labels=companies, colors=colors_comparison,
            autopct='%1.1f%%', startangle=90)
axes[0].set_title('饼图', fontsize=14, fontweight='bold')

# 右:条形图
bars = axes[1].bar(companies, market_share,
                   color=colors_comparison, alpha=0.8)
axes[1].set_title('条形图', fontsize=14, fontweight='bold')
axes[1].set_ylabel('市场份额(%)', fontsize=12)
axes[1].grid(axis='y', alpha=0.3)

# 添加数值标签
for bar in bars:
    height = bar.get_height()
    axes[1].text(bar.get_x() + bar.get_width()/2., height,
                f'{height}%', ha='center', va='bottom', fontsize=10)

plt.tight_layout()
plt.show()
Figure 2: 对比——条形图与饼图

嵌套饼图:多层级数据展示

import matplotlib.pyplot as plt

# ==================== 外层:大类资产 ====================
major_assets = ['权益类', '固定收益类', '另类投资']
major_alloc = [50, 35, 15]

# ==================== 内层:细分类别 ====================
sub_assets = ['A股', '港股', '国债', '信用债', '商品', 'REITs']
sub_alloc = [30, 20, 20, 15, 8, 7]

fig, ax = plt.subplots(figsize=(10, 10))

# 内层饼图
ax.pie(sub_alloc, radius=0.7, labels=sub_assets,
       colors=['#E3120B', '#F0656E', '#008080', '#46A1A8',
               '#F0A700', '#F7C555'],
       autopct='%1.1f%%', startangle=90,
       pctdistance=0.85, labeldistance=0.6)

# 外层饼图
ax.pie(major_alloc, radius=1.0, labels=major_assets,
       colors=['#E3120B', '#008080', '#F0A700'],
       autopct='%1.1f%%', startangle=90,
       labeldistance=1.05,
       textprops={'fontsize': 12, 'fontweight': 'bold'})

plt.title('投资组合多层级构成', fontsize=16, fontweight='bold', pad=20)
plt.tight_layout()
plt.show()
Figure 3: 嵌套饼图——多层级数据展示

金融应用:基金行业配置分析

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd

# ==================== 行业配置数据 ====================
industries = ['金融', '科技', '消费', '医疗', '新能源', '原材料', '其他']
fund_allocation = [25, 20, 18, 12, 10, 8, 7]
benchmark_allocation = [22, 15, 20, 10, 12, 10, 11]

fig, axes = plt.subplots(1, 2, figsize=(14, 7))

# 左:基金配置(饼图)
axes[0].pie(fund_allocation, labels=industries,
            autopct='%1.1f%%', startangle=90,
            colors=['#2E86AB', '#008080', '#E3120B', '#F0A700',
                    '#2C3E50', '#8E9EAA', '#A8B5BF'])
axes[0].set_title('基金行业配置', fontsize=14, fontweight='bold')

# 右:与基准对比(条形图)
x = np.arange(len(industries))
width = 0.35
axes[1].bar(x - width/2, fund_allocation, width,
           label='基金', color='#2E86AB', alpha=0.8)
axes[1].bar(x + width/2, benchmark_allocation, width,
           label='基准', color='#E3120B', alpha=0.8)
axes[1].set_xlabel('行业', fontsize=12)
axes[1].set_ylabel('配置比例(%)', fontsize=12)
axes[1].set_title('vs 基准对比', fontsize=14, fontweight='bold')
axes[1].set_xticks(x)
axes[1].set_xticklabels(industries, rotation=45)
axes[1].legend(fontsize=11)
axes[1].grid(axis='y', alpha=0.3)

plt.tight_layout()
plt.show()
Figure 4: 基金行业配置分析

饼图使用的最佳实践

适合使用饼图的场景

  • 展示部分与整体的关系
  • 类别较少(≤6个)
  • 各部分比例差异明显

不适合使用饼图的场景

  • 类别过多(>8个)
  • 需要精确比较数值
  • 各部分比例相近(难以区分)

饼图设计技巧

  1. 排序:按大小顺时针排列,从12点开始
  2. 突出关键:用 explode 或颜色突出重点
  3. 颜色:使用对比色,避免彩虹色
  4. 标签:直接标注,避免图例来回对照
  5. 总数:在标题或中心说明总数值

本章小结

  • 饼图:展示部分与整体关系的经典工具
  • 环形图:更现代美观,中心可添加信息
  • 嵌套饼图:展示多层级数据结构
  • 选择原则:类别少用饼图,类别多用条形图
  • 关键参数autopctstartangleexplode